//
//  RxWebViewController.m
//  RxWebViewController
//
//  Created by roxasora on 15/10/23.
//  Copyright © 2015年 roxasora. All rights reserved.
//

#import "RxWebViewController.h"
#import "NJKWebViewProgressView.h"
#import "UIImage+Tint.h"
#import "UIView+Frame.h"

#define boundsWidth self.view.bounds.size.width
#define boundsHeight self.view.bounds.size.height

static void *WebViewObserverContext = &WebViewObserverContext;

@interface RxWebScript : NSObject

@property(nonatomic, copy)NSString *scriptName;

@property(nonatomic, copy)void (^scriptComplete)(WKScriptMessage *scriptMessage);

@end

@implementation RxWebScript


@end

@interface RxWebViewController () <UINavigationControllerDelegate,UINavigationBarDelegate, UINavigationBarDelegate, WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler>

@property (nonatomic, strong) NSMutableArray <RxWebScript *>* scriptArray;

@property (nonatomic)UIBarButtonItem *closeButtonItem;

@property (nonatomic)NJKWebViewProgressView *progressView;

/**
 *  array that hold snapshots
 */
@property (nonatomic)NSMutableArray *snapShotsArray;

/**
 *  current snapshotview displaying on screen when start swiping
 */
@property (nonatomic)UIView *currentSnapShotView;

/**
 *  previous view
 */
@property (nonatomic)UIView *prevSnapShotView;


/**
 * navigaton background view
 */
//@property (nonatomic)UIView *navigationBackView;

/**
 *  background alpha black view
 */
@property (nonatomic)UIView *swipingBackgoundView;

/**
 *  left pan ges
 */
@property (nonatomic)UIPanGestureRecognizer *swipePanGesture;

/**
 *  if is swiping now
 */
@property (nonatomic)BOOL isSwipingBack;


@end

@implementation RxWebViewController

#pragma mark - init
- (instancetype)initWithUrl:(NSURL *)url
{
    self = [super init];
    if (self) {
        
        self.statusType = UIStatusBarStyleDefault;
        self.showWebTitel = NO;
        
        self.url = url;
        _progressViewColor = [UIColor colorWithRed:119.0/255 green:228.0/255 blue:115.0/255 alpha:1];
        self.navgationbackColor = [UIColor whiteColor];
    }
    return self;
}

- (instancetype)initWithHTML:(NSString*)htmlString{
    
    self = [super init];
    if (self) {
        
        self.statusType = UIStatusBarStyleDefault;
        self.showWebTitel = NO;
        
        self.htmlString = htmlString;
        _progressViewColor = [UIColor colorWithRed:119.0/255 green:228.0/255 blue:115.0/255 alpha:1];
    }
    return self;
}

- (void)addScriptName:(NSString *)scriptName withComplete:(void (^)(WKScriptMessage *scriptMessage))scriptComplete
{
    RxWebScript *webScript = [[RxWebScript alloc] init];
    webScript.scriptName = scriptName;
    webScript.scriptComplete = scriptComplete;
    
    [self.scriptArray addObject:webScript];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //config navigation item
    self.navigationItem.leftItemsSupplementBackButton = YES;
    
    [self.view addSubview:self.webView];
    
    if (self.url) {
        if ([self.url.absoluteString containsString:@"http"]||[self.url.absoluteString containsString:@"https"]) {
            [self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
        }else{
            [self.webView loadFileURL:self.url allowingReadAccessToURL:self.url];
        }
    }else{
        [self.webView loadHTMLString:self.htmlString baseURL:nil];
    }
    
    [self.webView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:NSKeyValueObservingOptionNew context:nil];
    
    __weak typeof(self) VC = self;
    [self.scriptArray enumerateObjectsUsingBlock:^(RxWebScript * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        WKUserContentController *userContentController = VC.webView.configuration.userContentController;
        [userContentController addScriptMessageHandler:VC name:obj.scriptName];
    }];
    
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.navigationController.navigationBar addSubview:self.progressView];
    if (self.presentingViewController) {
        
        UIButton * backButton = [[UIButton alloc] initWithFrame:CGRectMake(10, self.customNavagetionView.height-42, 60, 40)];
        [backButton setImage:[UIImage imageNamed:@"close_w"] forState:UIControlStateNormal];
        [backButton setImageEdgeInsets:UIEdgeInsetsMake(0, -30, 0, 0)];
        [backButton addTarget:self action:@selector(dismissViewController) forControlEvents:UIControlEventTouchUpInside];
        [self.customNavagetionView addSubview:backButton];
    }

}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [self.progressView removeFromSuperview];
    
}


#pragma mark - public funcs
- (void)reloadWebView
{
    [self.webView reload];
}

- (void)webReloadData {
    if (self.url) {
        if ([self.url.absoluteString containsString:@"http"]||[self.url.absoluteString containsString:@"https"]) {
            [self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
        }else{
            [self.webView loadFileURL:self.url allowingReadAccessToURL:self.url];
        }
    }else{
        [self.webView loadHTMLString:self.htmlString baseURL:nil];
    }
}

#pragma mark - logic of push and pop snap shot views
- (void)pushCurrentSnapshotViewWithRequest:(NSURLRequest *)request
{
    NSURLRequest *lastRequest = (NSURLRequest*)[[self.snapShotsArray lastObject] objectForKey:@"request"];
    
    if ([request.URL.absoluteString isEqualToString:@"about:blank"]) {
        return;
    }
    
    if ([lastRequest.URL.absoluteString isEqualToString:request.URL.absoluteString]) {
        return;
    }
    
    UIView *currentSnapShotView = [self.webView snapshotViewAfterScreenUpdates:YES];
    [self.snapShotsArray addObject:@{@"request":request, @"snapShotView":currentSnapShotView}];
}

- (void)startPopSnapshotView
{
    if (self.isSwipingBack) {
        return;
    }
    if (!self.webView.canGoBack) {
        return;
    }
    self.isSwipingBack = YES;
    
    CGPoint center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2);
    
    self.currentSnapShotView = [self.webView snapshotViewAfterScreenUpdates:YES];
    
    self.currentSnapShotView.layer.shadowColor = [UIColor blackColor].CGColor;
    self.currentSnapShotView.layer.shadowOffset = CGSizeMake(3, 3);
    self.currentSnapShotView.layer.shadowRadius = 5;
    self.currentSnapShotView.layer.shadowOpacity = 0.75;
    
    self.currentSnapShotView.center = center;
    
    self.prevSnapShotView = (UIView*)[[self.snapShotsArray lastObject] objectForKey:@"snapShotView"];
    center.x -= 60;
    self.prevSnapShotView.center = center;
    self.prevSnapShotView.alpha = 1;
    self.view.backgroundColor = [UIColor blackColor];
    
    [self.view addSubview:self.prevSnapShotView];
    [self.view addSubview:self.swipingBackgoundView];
    [self.view addSubview:self.currentSnapShotView];
}

- (void)popSnapShotViewWithPanGestureDistance:(CGFloat)distance
{
    if (!self.isSwipingBack) {
        return;
    }
    
    if (distance <= 0) {
        return;
    }
    
    CGPoint currentSnapshotViewCenter = CGPointMake(boundsWidth/2, boundsHeight/2);
    currentSnapshotViewCenter.x += distance;
    CGPoint prevSnapshotViewCenter = CGPointMake(boundsWidth/2, boundsHeight/2);
    prevSnapshotViewCenter.x -= (boundsWidth - distance)*60/boundsWidth;
    
    self.currentSnapShotView.center = currentSnapshotViewCenter;
    self.prevSnapShotView.center = prevSnapshotViewCenter;
    self.swipingBackgoundView.alpha = (boundsWidth - distance)/boundsWidth;
}

- (void)endPopSnapShotView
{
    if (!self.isSwipingBack) {
        return;
    }
    
    self.view.userInteractionEnabled = NO;
    
    if (self.currentSnapShotView.center.x >= boundsWidth) {
        [UIView animateWithDuration:0.2 animations:^{
            [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
            
            self.currentSnapShotView.center = CGPointMake(boundsWidth*3/2, boundsHeight/2);
            self.prevSnapShotView.center = CGPointMake(boundsWidth/2, boundsHeight/2);
            self.swipingBackgoundView.alpha = 0;
        }completion:^(BOOL finished) {
            [self.prevSnapShotView removeFromSuperview];
            [self.swipingBackgoundView removeFromSuperview];
            [self.currentSnapShotView removeFromSuperview];
            [self.webView goBack];
            [self.snapShotsArray removeLastObject];
            self.view.userInteractionEnabled = YES;
            
            self.isSwipingBack = NO;
        }];
    }else{
        [UIView animateWithDuration:0.2 animations:^{
            [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
            
            self.currentSnapShotView.center = CGPointMake(boundsWidth/2, boundsHeight/2);
            self.prevSnapShotView.center = CGPointMake(boundsWidth/2-60, boundsHeight/2);
            self.prevSnapShotView.alpha = 1;
        }completion:^(BOOL finished) {
            [self.prevSnapShotView removeFromSuperview];
            [self.swipingBackgoundView removeFromSuperview];
            [self.currentSnapShotView removeFromSuperview];
            self.view.userInteractionEnabled = YES;
            
            self.isSwipingBack = NO;
        }];
    }
}

#pragma mark - update nav items

- (void)updateNavigationItems
{
    /* 暂时不处理
    if (self.webView.canGoBack) {
        UIBarButtonItem *spaceButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
        spaceButtonItem.width = -6.5;
        
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
        [self.navigationItem setLeftBarButtonItems:@[self.closeButtonItem] animated:NO];
        
    }else{
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        [self.navigationItem setLeftBarButtonItems:nil];
    }
     */
}

#pragma mark - events handler
- (void)swipePanGestureHandler:(UIPanGestureRecognizer*)panGesture
{
    CGPoint translation = [panGesture translationInView:self.webView];
    CGPoint location = [panGesture locationInView:self.webView];
    
    if (panGesture.state == UIGestureRecognizerStateBegan) {
        if (location.x <= 50 && translation.x > 0) {  //开始动画
            [self startPopSnapshotView];
        }
    }else if (panGesture.state == UIGestureRecognizerStateCancelled || panGesture.state == UIGestureRecognizerStateEnded){
        [self endPopSnapShotView];
    }else if (panGesture.state == UIGestureRecognizerStateChanged){
        [self popSnapShotViewWithPanGestureDistance:translation.x];
    }
}

- (void)customBackItemClicked
{
    [self.webView goBack];
}

- (void)closeItemClicked
{
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    [self.scriptArray enumerateObjectsUsingBlock:^(RxWebScript * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([message.name isEqualToString:obj.scriptName]) {
            (obj.scriptComplete)? obj.scriptComplete(message) : nil;
        }
    }];
}

#pragma mark - webView delegate
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
    self.progressView.hidden = NO;
}

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    switch (navigationAction.navigationType) {
        case WKNavigationTypeLinkActivated: {
            [self pushCurrentSnapshotViewWithRequest:navigationAction.request];
            break;
        }
        case WKNavigationTypeFormSubmitted: {
            [self pushCurrentSnapshotViewWithRequest:navigationAction.request];
            break;
        }
        case WKNavigationTypeBackForward: {
            break;
        }
        case WKNavigationTypeReload: {
            break;
        }
        case WKNavigationTypeFormResubmitted: {
            break;
        }
        case WKNavigationTypeOther: {
            [self pushCurrentSnapshotViewWithRequest:navigationAction.request];
            break;
        }
        default: {
            break;
        }
    }
    [self updateNavigationItems];
    decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    [self updateNavigationItems];
    if (_showWebTitel) self.customTitel = self.webView.title;
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation
{
    [self.progressView setProgress:0.0f animated:YES];
}

#pragma mark - NJProgress delegate

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && [object isKindOfClass:[WKWebView class]]) {
        WKWebView *webView = (WKWebView *)object;
        [self.progressView setAlpha:1.0f];
        if (webView.loading) {
            BOOL animated = webView.estimatedProgress > self.progressView.progress;
            [self.progressView setProgress:webView.estimatedProgress animated:animated];
            
            if (self.webView.estimatedProgress >= 1.0f) {
                [UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
                    [self.progressView setAlpha:0.0f];
                } completion:^(BOOL finished) {
                    [self.progressView setProgress:0.0f animated:NO];
                }];
            }
        }else {
            [self.progressView setProgress:0.0f animated:NO];
        }
    }else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)popAction{
    
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark - setters and getters

//- (void)setNavgationbackColor:(UIColor *)navgationbackColor{
//
//    self.navigationBackView.backgroundColor = navgationbackColor;
//}

- (void)setUrl:(NSURL *)url
{
    _url = url;
}

- (void)setProgressViewColor:(UIColor *)progressViewColor
{
    _progressViewColor = progressViewColor;
    self.progressView.progressColor = progressViewColor;
}

- (WKWebView *)webView
{
    if (!_webView) {
        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
        configuration.allowsInlineMediaPlayback = YES;
        configuration.selectionGranularity = YES;
        
        configuration.processPool = [[WKProcessPool alloc] init];
        
        NSString *js = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
        WKUserScript *script = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        [userContentController addUserScript:script];
        configuration.suppressesIncrementalRendering = YES;
        configuration.userContentController = userContentController;
        
        _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
        
        _webView.backgroundColor = [UIColor whiteColor];
        _webView.navigationDelegate = self;
        _webView.UIDelegate = self;
        _webView.allowsBackForwardNavigationGestures = YES;
        [_webView addGestureRecognizer:self.swipePanGesture];
        [_webView sizeToFit];
        
    }
    return _webView;
}

- (void)setShowNavigation:(BOOL)showNavigation{
    
    _showNavigation = showNavigation;
    
    if (_showNavigation) {
        CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
        CGFloat navbarHeight = self.navigationController.navigationBar.frame.size.height;
        CGFloat totalHeight = statusBarHeight + navbarHeight ;
        CGRect frame = CGRectMake(0, totalHeight, self.view.bounds.size.width, self.view.bounds.size.height-totalHeight);
        
        _webView.frame = frame ;
    }
}

- (UIBarButtonItem *)closeButtonItem
{
    if (!_closeButtonItem) {
        UIButton *colseButton = [UIButton buttonWithType:UIButtonTypeCustom];
        colseButton.frame = CGRectMake(0, 0, 22, 22);
        [colseButton addTarget:self action:@selector(closeItemClicked) forControlEvents:UIControlEventTouchUpInside];
        [colseButton setImage:[UIImage imageNamed:@"close_w"] forState:UIControlStateNormal];
        _closeButtonItem = [[UIBarButtonItem alloc] initWithCustomView:colseButton];
    }
    return _closeButtonItem;
}

- (UIView *)swipingBackgoundView
{
    if (!_swipingBackgoundView) {
        _swipingBackgoundView = [[UIView alloc] initWithFrame:self.view.bounds];
        _swipingBackgoundView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
    }
    return _swipingBackgoundView;
}

- (NSMutableArray *)snapShotsArray
{
    if (!_snapShotsArray) {
        _snapShotsArray = [NSMutableArray array];
    }
    return _snapShotsArray;
}

- (BOOL)isSwipingBack
{
    if (!_isSwipingBack) {
        _isSwipingBack = NO;
    }
    return _isSwipingBack;
}

- (NSMutableArray *)scriptArray
{
    if (!_scriptArray) {
        _scriptArray = [NSMutableArray array];
    }
    return _scriptArray;
}

- (UIPanGestureRecognizer *)swipePanGesture
{
    if (!_swipePanGesture) {
        _swipePanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(swipePanGestureHandler:)];
    }
    return _swipePanGesture;
}

- (NJKWebViewProgressView *)progressView
{
    if (!_progressView) {
        CGFloat progressBarHeight = 2.0f;
        CGRect navigaitonBarBounds = self.navigationController.navigationBar.bounds;
        CGRect barFrame = CGRectMake(0, navigaitonBarBounds.size.height, navigaitonBarBounds.size.width, progressBarHeight);
        _progressView = [[NJKWebViewProgressView alloc] initWithFrame:barFrame];
        _progressView.progressColor = self.progressViewColor;
        _progressView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
        _progressView.hidden = YES;
    }
    return _progressView;
}

- (void)dealloc{
    [self.webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) context:nil];
    [self.webView.configuration.userContentController removeAllUserScripts];
}

@end
